package com.baturu.mybatisminus.util;


import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ClassUtils {

    /**
     * 判断是否为代理对象
     */
    public static boolean isProxy(Class<?> clazz) {
        if (clazz != null) {
            for (Class<?> cls : clazz.getInterfaces()) {
                String interfaceName = cls.getName();
                if (interfaceName.equals("net.sf.cglib.proxy.Factory") //cglib
                        || interfaceName.equals("org.springframework.cglib.proxy.Factory")
                        || interfaceName.equals("javassist.util.proxy.ProxyObject") //javassist
                        || interfaceName.equals("org.apache.ibatis.javassist.util.proxy.ProxyObject")) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 获取当前对象的class
     */
    public static Class<?> getUserClass(Class<?> clazz) {
        return isProxy(clazz) ? clazz.getSuperclass() : clazz;
    }

    /**
     * 获取当前对象的class
     */
    public static Class<?> getUserClass(Object object) {
        return getUserClass(object.getClass());
    }

    /**
     * 获取用户定义的方法
     */
    public static List<Method> getCustomerMethod(Class<?> mapperClass) {
        if (mapperClass == null) {
            return Collections.emptyList();
        }
        Method[] methods = mapperClass.getMethods();
        return Arrays.stream(methods)
                .filter(m -> mapperClass.equals(m.getDeclaringClass()) && isNotDefaultMethod(m))
                .collect(Collectors.toList());
    }


    /**
     * 检查类中不存在重复的方法名
     * @throws IllegalStateException 当存在重复方法名时抛出异常
     */
    public static void checkMethodNameNotRepeat(Class<?> clazz) {
        Objects.requireNonNull(clazz);
        Set<String> methodNameSet = new HashSet<>();
        Stream.of(clazz.getMethods())
                .filter(m -> Modifier.isAbstract(m.getModifiers()))
                .map(Method::getName)
                .forEach(methodName -> {
                    if (!methodNameSet.add(methodName)) {
                        throw new IllegalStateException(clazz.getName() + "类中方法名重复:" + methodName);
                    }
                });
    }


    private static boolean isNotDefaultMethod(Method method) {
        return !((method.getModifiers()
                & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC
                && method.getDeclaringClass().isInterface());
    }

}
